package com.young.netty.gateway.interceptor;

import com.young.netty.gateway.context.HttpContext;
import com.young.netty.gateway.exception.ErrorCodeEnum;
import com.young.netty.gateway.exception.NettyGatewayException;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;

/**
 * 拦截器链对象
 *
 * @author Young
 * @Date 2021-07-24 19:39
 */
public class InterceptorChain {

    /**
     * 拦截器Map
     * key-拦截器顺序，value-拦截器对象
     * 按照key的升序排序
     */
    private static Map<String, Interceptor> INTERCEPTOR_MAP = new TreeMap<>(Comparator.naturalOrder());

    /**
     * 正向拦截器
     */
    private List<Interceptor> forwardInterceptor;

    /**
     * 反向拦截器
     */
    private List<Interceptor> reverseInterceptor;

    /**
     * 未排序标志位
     */
    private boolean unsortedFlag = true;

    public void addInterceptor(String order, Interceptor interceptor) {
        if (Objects.nonNull(INTERCEPTOR_MAP.get(order))) {
            throw new NettyGatewayException(ErrorCodeEnum.ERROR001);
        }
        INTERCEPTOR_MAP.put(order, interceptor);
    }

    /**
     * 执行拦截器
     *
     * @param httpContext
     */
    public void execute(HttpContext httpContext) {
        if (unsortedFlag) {
            sortInterceptor();
        }
        try {
            forwardInterceptor.stream().forEach(interceptor -> interceptor.parse(httpContext));
            forwardInterceptor.stream().forEach(interceptor -> interceptor.route(httpContext));
            reverseInterceptor.stream().forEach(interceptor -> interceptor.completed(httpContext));
        } catch (Exception e) {
            reverseInterceptor.stream().forEach(interceptor -> interceptor.exception(httpContext, e));
        }
    }

    /**
     * 排序
     */
    private void sortInterceptor() {
        forwardInterceptor = new ArrayList<>();
        forwardInterceptor.addAll(INTERCEPTOR_MAP.values());
        for (int i = forwardInterceptor.size(); i >= 0; i--) {
            reverseInterceptor.add(forwardInterceptor.get(i));
        }
    }

}
